﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

namespace Ue.Infrastructure.Data
{
    public abstract class RepositoryBase<TEntity,TKey> : IRepository<TEntity,TKey>, IUnitOfWorkRepository<TEntity,TKey>
        where TEntity : IEntity<TKey>
    {
        #region Constructors and Fields

        private IUnitOfWork unitOfWork;

        protected RepositoryBase()
            : this(null) { }

        protected RepositoryBase(IUnitOfWork unitOfWork)
        {
            this.unitOfWork = unitOfWork;
        }

        #endregion

        #region Properties

        protected IUnitOfWork UnitOfWork
        {
            get { return this.unitOfWork; }
        }

        #endregion

        #region Methods

        protected abstract void PersistNewItem(TEntity item);
        protected abstract void PersistUpdatedItem(TEntity item);
        protected abstract void PersistDeletedItem(TEntity item);

        #endregion

        #region IRepository Members

        public abstract IQueryable<TEntity> Table { get; }

        public abstract bool ContainsKey(TKey key);

        public abstract bool Contains(TEntity entity);

        public abstract TEntity FindBy(TKey key);

        public abstract IEnumerable<TEntity> FindBy(Expression<Func<TEntity, bool>> predicate);
        public abstract IEnumerable<TEntity> FindBy(Expression<Func<TEntity, bool>> predicate, int skip, int count);

        public abstract int Count(Expression<Func<TEntity, bool>> predicate);

        public void Add(TEntity item)
        {
            if (this.unitOfWork != null)
            {
                this.unitOfWork.RegisterAdded(item, this);
            }
            else
            {
                this.PersistNewItem(item);
            }
        }

        public void Remove(TEntity item)
        {
            if (this.unitOfWork != null)
            {
                this.unitOfWork.RegisterDeleted(item, this);
            }
            else
            {
                this.PersistDeletedItem(item);
            }
        }

        public TEntity this[TKey key]
        {
            get
            {
                return this.FindBy(key);
            }
            set
            {
                if (this.ContainsKey(key))
                {
                    if (this.unitOfWork != null)
                    {
                        this.unitOfWork.RegisterModified(value, this);
                    }
                    else
                    {
                        this.PersistUpdatedItem(value);
                    }
                }
                else
                {
                    this.Add(value);
                }
            }
        }

        #endregion

        #region IUnitOfWorkRepository

        void IUnitOfWorkRepository<TEntity, TKey>.PersistNewItem(TEntity item)
        {
            this.PersistNewItem(item);
        }

        void IUnitOfWorkRepository<TEntity, TKey>.PersistUpdatedItem(TEntity item)
        {
            this.PersistUpdatedItem(item);
        }

        void IUnitOfWorkRepository<TEntity, TKey>.PersistDeletedItem(TEntity item)
        {
            this.PersistDeletedItem(item);
        }

        #endregion
    }
}
